﻿
Public Module _time

    'microseconds to milliseconds, *1000
    'ticks to milliseconds, /10000
    'milliseconds to seconds, /1000

    Public Function millisecondsToMicroseconds(ByVal ms As Int64) As Int64
        Return ms * 1000
    End Function

    Public Function microsecondsToMilliseconds(ByVal ms As Int64) As Int64
        Return ms \ 1000
    End Function

    Public Function ticksToMilliseconds(ByVal ticks As Int64) As Int64
        Return ticks \ 10000
    End Function

    Public Function millisecondsToTicks(ByVal ms As Int64) As Int64
        Try
            Return ms * 10000
        Catch
            Return maxInt64
        End Try
    End Function

    Public Function millisecondsToSeconds(ByVal ms As Int64) As Int64
        Return ms \ 1000
    End Function

    Public Function secondsToMilliseconds(ByVal s As Int64) As Int64
        Try
            Return s * 1000
        Catch
            Return maxInt64
        End Try
    End Function

    Public Function ticksToSeconds(ByVal ticks As Int64) As Int64
        Return ticks \ 1000 \ 10000
    End Function

    Public Function secondsToTicks(ByVal s As Int64) As Int64
        Try
            Return s * 1000 * 10000
        Catch
            Return maxInt64
        End Try
    End Function

    Public Function longTime(ByVal d As Date) As String
        Return d.ToLongDateString() + character.comma + character.blank + d.ToLongTimeString()
    End Function

    Public Function longTime(Optional ByVal timezone As Int64 = maxInt64) As String
        Return longTime(getTimezoneDate(timezone))
    End Function

    Public Function shortTime(ByVal d As Date, _
                              Optional ByVal datetimeSeperator As String = character.blank, _
                              Optional ByVal dateSeperator As String = character.minusSign, _
                              Optional ByVal timeSeperator As String = character.colon) As String
        Return strright(Convert.ToString(d.Year), 2) _
                + dateSeperator + strrfill(Convert.ToString(d.Month), character._0, 2) _
                + dateSeperator + strrfill(Convert.ToString(d.Day), character._0, 2) _
                + datetimeSeperator _
                + strrfill(Convert.ToString(d.Hour), character._0, 2) _
                + timeSeperator + strrfill(Convert.ToString(d.Minute), character._0, 2) _
                + timeSeperator + strrfill(Convert.ToString(d.Second), character._0, 2)
    End Function

    Public Function shortTime(Optional ByVal datetimeSeperator As String = character.blank, _
                              Optional ByVal dateSeperator As String = character.minusSign, _
                              Optional ByVal timeSeperator As String = character.colon, _
                              Optional ByVal timezone As Int64 = maxInt64) As String
        Return shortTime(getTimezoneDate(timezone), datetimeSeperator, dateSeperator, timeSeperator)
    End Function

    Public Function getTimezoneDate(Optional ByVal timezone As Int64 = maxInt64) As Date
        Return getTimezoneDate(Now, timezone)
    End Function

    Public Function getTimezoneDate(ByVal d As Date, Optional ByVal timezone As Int64 = maxInt64) As Date
        If timezone = maxInt64 Then
            'if no timezone defined, just use local time
            Return d
        Else
            Return d.ToUniversalTime().AddMinutes(timezone)
        End If
    End Function

    Public Function toGMTTime(ByVal d As Date) As String
        Return d.ToString("r")
    End Function

    Public Function thisyear(ByVal d As Date) As Date
        d = thismonth(d)
        'month is 1-based
        Return d.AddMonths(-d.Month() + 1)
    End Function

    Public Function lastyear(ByVal d As Date) As Date
        d = thisyear(d)
        Return d.AddYears(-1)
    End Function

    Public Function thisyear(ByVal tick As Int64) As Int64
        Return thisyear(New Date(tick)).Ticks()
    End Function

    Public Function lastyear(ByVal tick As Int64) As Int64
        Return lastyear(New Date(tick)).Ticks()
    End Function

    'return 00:00 of the first day of this month
    Public Function thismonth(ByVal d As Date) As Date
        d = thisday(d)
        'day is 1-based
        Return d.AddDays(-d.Day() + 1)
    End Function

    Public Function lastmonth(ByVal d As Date) As Date
        d = thismonth(d)
        Return d.AddMonths(-1)
    End Function

    Public Function thismonth(ByVal tick As Int64) As Int64
        Return thismonth(New Date(tick)).Ticks()
    End Function

    Public Function lastmonth(ByVal tick As Int64) As Int64
        Return lastmonth(New Date(tick)).Ticks()
    End Function

    Public Function thisweek(ByVal d As Date) As Date
        d = thisday(d)
        Return d.AddDays(-d.DayOfWeek())
    End Function

    Public Function lastweek(ByVal d As Date) As Date
        d = thisweek(d)
        Return d.AddDays(-daysInWeek)
    End Function

    Public Function thisweek(ByVal tick As Int64) As Int64
        Return thisweek(New Date(tick)).Ticks()
    End Function

    Public Function lastweek(ByVal tick As Int64) As Int64
        Return lastweek(New Date(tick)).Ticks()
    End Function

    'return 00:00 of this day
    Public Function thisday(ByVal d As Date) As Date
        d = thishour(d)
        Return d.AddHours(-d.Hour())
    End Function

    Public Function lastday(ByVal d As Date) As Date
        d = thisday(d)
        Return d.AddDays(-1)
    End Function

    Public Function thisday(ByVal tick As Int64) As Int64
        Return thisday(New Date(tick)).Ticks()
    End Function

    Public Function lastday(ByVal tick As Int64) As Int64
        Return lastday(New Date(tick)).Ticks()
    End Function

    Public Function thishour(ByVal d As Date) As Date
        d = thisminute(d)
        Return d.AddMinutes(-d.Minute())
    End Function

    Public Function lasthour(ByVal d As Date) As Date
        d = thishour(d)
        Return d.AddHours(-1)
    End Function

    Public Function thishour(ByVal tick As Int64) As Int64
        Return thishour(New Date(tick)).Ticks()
    End Function

    Public Function lasthour(ByVal tick As Int64) As Int64
        Return lasthour(New Date(tick)).Ticks()
    End Function

    Public Function thisminute(ByVal d As Date) As Date
        d = thissecond(d)
        Return d.AddSeconds(-d.Second())
    End Function

    Public Function lastminute(ByVal d As Date) As Date
        d = thisminute(d)
        Return d.AddMinutes(-1)
    End Function

    Public Function thisminute(ByVal tick As Int64) As Int64
        Return thisminute(New Date(tick)).Ticks()
    End Function

    Public Function lastminute(ByVal tick As Int64) As Int64
        Return lastminute(New Date(tick)).Ticks()
    End Function

    Public Function thissecond(ByVal d As Date) As Date
        d = thismillisecond(d)
        Return d.AddMilliseconds(-d.Millisecond())
    End Function

    Public Function lastsecond(ByVal d As Date) As Date
        d = thissecond(d)
        Return d.AddSeconds(-1)
    End Function

    Public Function thissecond(ByVal tick As Int64) As Int64
        Return thissecond(New Date(tick)).Ticks()
    End Function

    Public Function lastsecond(ByVal tick As Int64) As Int64
        Return lastsecond(New Date(tick)).Ticks()
    End Function

    Public Function thismillisecond(ByVal d As Date) As Date
        Static ticksOfMilliseconds As Int64 = millisecondsToTicks(1)
        Return d.AddTicks(-(d.Ticks() Mod ticksOfMilliseconds))
    End Function

    Public Function lastmillisecond(ByVal d As Date) As Date
        d = thismillisecond(d)
        Return d.AddMilliseconds(-1)
    End Function

    Public Function thismillisecond(ByVal tick As Int64) As Int64
        Return thismillisecond(New Date(tick)).Ticks()
    End Function

    Public Function lastmillisecond(ByVal tick As Int64) As Int64
        Return lastmillisecond(New Date(tick)).Ticks()
    End Function

#If PocketPC OrElse Smartphone Then
    Public Function DateTryParse(ByVal input As String, ByRef o As Date) As Boolean
        Try
            o = Date.Parse(input)
        Catch ex As Exception
            Return False
        End Try

        Return True
    End Function
#End If

    Public Class unittests
        Private Delegate Function thisDelegate(ByVal d As Date) As Date
        Private Delegate Function thisDelegate2(ByVal tick As Int64) As Int64

        Private Shared Sub this(ByVal d As Date, ByVal name As String, ByVal t As thisDelegate)
            Console.WriteLine(name + " " + Convert.ToString(t(d)))
        End Sub

        Private Shared Sub this2(ByVal d As Date, ByVal name As String, ByVal t As thisDelegate2)
            Console.WriteLine(name + " " + Convert.ToString(t(d.Ticks())))
        End Sub

        Public Shared Sub these()
            Console.WriteLine("input a time")
            Dim input As String = Nothing
            input = Console.ReadLine()
            While Not input Is Nothing
                Dim d As Date = Nothing
#If PocketPC OrElse Smartphone Then
                If DateTryParse(input, d) Then
#Else
                If Date.TryParse(input, d) Then
#End If
                    this(d, "thissecond", AddressOf thissecond)
                    this2(d, "thissecond", AddressOf thissecond)
                    this(d, "thisminute", AddressOf thisminute)
                    this2(d, "thisminute", AddressOf thisminute)
                    this(d, "thishour", AddressOf thishour)
                    this2(d, "thishour", AddressOf thishour)
                    this(d, "thisday", AddressOf thisday)
                    this2(d, "thisday", AddressOf thisday)
                    this(d, "thismonth", AddressOf thismonth)
                    this2(d, "thismonth", AddressOf thismonth)
                    this(d, "thisyear", AddressOf thisyear)
                    this2(d, "thisyear", AddressOf thisyear)
                Else
                    raiseError("cannot parse input as DateTime, " + input, errorHandle.errorType.user)
                End If
                input = Console.ReadLine()
            End While
        End Sub
    End Class
End Module
